编程之美----俄罗斯方块

编程之美----俄罗斯方块

问题:

让电脑自动下俄罗斯方块游戏。


解法:

对当前的积木块,枚举它旋转后的每一个形状从每一列落下的棋盘,将该棋盘和前一个棋盘进行对比,并打分,最后取得分最高的那个形状和那一列作为电脑的当前操作。

  1. #include <iostream>  
  2. #include <algorithm>  
  3. #include <cstdlib>  
  4. #include <ctime>  
  5. using namespace std;  
  6.   
  7. // 积木块的信息  
  8. #define BLOCK_SIZE  7  
  9. #define ROTATE_SIZE 4  
  10. #define SIDE_LEN    4  
  11. const int BLOCK_AREA = SIDE_LEN*SIDE_LEN;  
  12. // 棋盘的信息  
  13. #define HORIZ_LEN   12  
  14. #define VERT_LEN    15  
  15. const int CHESS_AREA = HORIZ_LEN*VERT_LEN;  
  16. // 其它信息  
  17. #define TOP_STEP    25  
  18. #define inf         10000  
  19. // 计分信息  
  20. const int clearLineScore[] = {0, 1, 3, 7, 13};  
  21.   
  22. struct Block    // 积木块  
  23. {  
  24.     void init(unsigned char *l)   
  25.     {  
  26.         memcpy(layout, l, BLOCK_AREA);  
  27.         int i, j;  
  28.         for (i=0; i<SIDE_LEN; i++)  
  29.         {  
  30.             for (j=SIDE_LEN-1; j>=0 && layout[j*SIDE_LEN+i]==0; j--);  
  31.             maxRow[i] = j+1;  
  32.         }  
  33.         for(i=0; i<SIDE_LEN && maxRow[i]==0; i++);  
  34.         minCol = i;  
  35.         for (i=SIDE_LEN-1; i>=0 && maxRow[i]==0; i--);  
  36.         maxCol = i;  
  37.     }  
  38.     unsigned char layout[BLOCK_AREA];   // 积木块的布局  
  39.     unsigned char maxRow[SIDE_LEN];     // 积木块每一列所占区域的最大行,取值从1开始  
  40.     unsigned char minCol;               // 积木块所占区域的最小值列和最大列,取值从0开始  
  41.     unsigned char maxCol;  
  42. };  
  43.   
  44. Block blockSet[BLOCK_SIZE][ROTATE_SIZE];    // 7种积木块,每种积木块有4种旋转方向  
  45. unsigned char chess[CHESS_AREA];        // 棋盘的布局  
  46. unsigned char nextChess[CHESS_AREA];    // 下一步棋盘的布局  
  47. int height[HORIZ_LEN];                  // 棋盘每一列所占区域的最小行,即高度  
  48.   
  49. void calcHeight(unsigned char *curchess)    // 计算当前棋盘的高度信息  
  50. {  
  51.     int i, j;  
  52.     for (i=0; i<HORIZ_LEN; i++)  
  53.     {  
  54.         for (j=0; j<VERT_LEN && curchess[j*HORIZ_LEN+i]==0; j++);  
  55.         height[i] = j;  
  56.     }  
  57. }  
  58.   
  59. // 计算若积木块从offsetX列落下,会落在第几行,即offsetY  
  60. int calcBottomOffsetY(const Block& b, int offsetX)    
  61. {  
  62.     int offsetY = VERT_LEN;  
  63.     for (int i=0; i<SIDE_LEN; i++)  
  64.     {  
  65.         if (b.maxRow[i]==0) continue;  
  66.         offsetY = min(offsetY, height[offsetX+i]-b.maxRow[i]);  
  67.     }  
  68.     return offsetY;  
  69. }  
  70.   
  71. // 将积木块贴到棋盘上  
  72. void pasteTo(unsigned char *curchess, const Block& b,  
  73.     int offsetX, int offsetY)  
  74. {  
  75.     for (int i=b.minCol; i<=b.maxCol; i++)  
  76.         for (int j=0; j<SIDE_LEN; j++)  
  77.         {  
  78.             unsigned char bij = b.layout[j*SIDE_LEN + i];  
  79.             unsigned char& cij = curchess[(j+offsetY)*HORIZ_LEN + i+offsetX];  
  80.             if (bij && cij==0)  
  81.                 cij = bij;  
  82.             else if (bij && cij)  
  83.                 cout << "ERROR" << endl;  
  84.         }  
  85. }  
  86.   
  87. // 消去[offsetY,offsetY+SIDE_LEN)中remline为1的行  
  88. void clearLines(unsigned char *curchess, int offsetY, unsigned char *remline)  
  89. {  
  90.     int i, j, gap=0;  
  91.     for (j=offsetY+SIDE_LEN-1; j>=0; j--)  
  92.     {  
  93.         if (j-offsetY>=0 && remline[j-offsetY])  
  94.             gap++;  
  95.         else if (gap)  
  96.         {  
  97.             memcpy(curchess+(j+gap)*HORIZ_LEN, curchess+j*HORIZ_LEN, HORIZ_LEN);  
  98.         }  
  99.     }  
  100. }  
  101.   
  102. // 计算[offsetX,offsetX+SIDE_LEN)列的洞的个数  
  103. int calcHoles(unsigned char *curchess, int offsetX, int offsetY)  
  104. {  
  105.     int i, j;  
  106.     int holeCount = 0;  
  107.     for (i=offsetX; i<offsetX+SIDE_LEN; i++)  
  108.     {  
  109.         if (i<0 || i>=HORIZ_LEN) continue;  
  110.         for (j=offsetY; j<VERT_LEN && curchess[j*HORIZ_LEN+i]==0; j++);  
  111.         for (; j<VERT_LEN; j++)  
  112.             if (curchess[j*HORIZ_LEN+i]==0)  
  113.                 holeCount++;  
  114.     }  
  115.     return holeCount;  
  116. }  
  117.   
  118. // 计算当前棋盘的得分  
  119. int calcScore(unsigned char *curchess, int offsetX, int offsetY)  
  120. {  
  121.     int i, j, score = 0;  
  122.     int remlineCount = 0;  
  123.     unsigned char remline[SIDE_LEN] = {0};  
  124.     // 统计消行数  
  125.     for (j=offsetY; j<offsetY+SIDE_LEN; j++)  
  126.     {  
  127.         for (i=0; i<HORIZ_LEN && curchess[j*HORIZ_LEN+i]; i++);  
  128.         if (i==HORIZ_LEN)   
  129.         {  
  130.             remlineCount++;  
  131.             remline[j-offsetY] = 1;  
  132.         }  
  133.     }  
  134.     score += clearLineScore[remlineCount];  
  135.     // 统计洞的个数  
  136.     if (remlineCount)  
  137.         clearLines(curchess, offsetY, remline);  
  138.     int holeCount = calcHoles(curchess, offsetX, offsetY) -   
  139.                     calcHoles(chess, offsetX, offsetY);  
  140.     score -= holeCount*4;  
  141.     // 位置过高则扣分  
  142.     if (holeCount > 5) score -= 15;  
  143.     if (offsetY-remlineCount < VERT_LEN*3/5)  
  144.         score -= VERT_LEN*3/5-(offsetY-remlineCount);  
  145.     return score;  
  146. }  
  147.   
  148. void output(unsigned char *curchess)  
  149. {  
  150.     for (int j=0; j<VERT_LEN; j++)  
  151.     {  
  152.         for (int i=0; i<HORIZ_LEN; i++)  
  153.             cout << curchess[j*HORIZ_LEN+i] << " ";  
  154.         cout << endl;  
  155.     }  
  156. }  
  157.   
  158. int main()  
  159. {  
  160.     srand(time(0));  
  161.     int i, j, k, n, m;  
  162.     // 初始化积木块  
  163.     for (i=0; i<BLOCK_SIZE; i++)  
  164.         for (j=0; j<ROTATE_SIZE; j++)  
  165.         {  
  166.             unsigned char l[BLOCK_AREA];  
  167.             for (k=0; k<BLOCK_AREA; k++)  
  168.                 scanf("%d",&l[k]);  
  169.             blockSet[i][j].init(l);  
  170.         }  
  171.     // 初始化棋盘  
  172.     for (i=0; i<CHESS_AREA; i++)  
  173.         scanf("%d",&chess[i]);  
  174.     // 显示前TOP_STEP步  
  175.     int offsetX, offsetY;  
  176.     unsigned char tmpchess[CHESS_AREA];  
  177.     for (n=TOP_STEP; n>=0; n--)  
  178.     {  
  179.         output(chess);  
  180.         calcHeight(chess);  // 为每一步计算一次height数组,避免计算offsetY时过多的重复计算  
  181.         int bind = rand()%BLOCK_SIZE;   // 积木块的序号  
  182.         int maxScore = -inf;  
  183.         for (j=0; j<ROTATE_SIZE; j++)    // 要考虑积木块的各种旋转情况  
  184.         {  
  185.             const Block& b = blockSet[bind][j];     // 得到当前的积木块  
  186.             for (offsetX=-b.minCol; offsetX<HORIZ_LEN-b.maxCol; offsetX++)  
  187.             {  
  188.                 // 计算从offsetX列落下,所落在棋盘的位置offsetY  
  189.                 offsetY = calcBottomOffsetY(b, offsetX);  
  190.                 if (offsetY<0) continue;  
  191.                 memcpy(tmpchess, chess, CHESS_AREA);  
  192.                 pasteTo(tmpchess, b, offsetX, offsetY); // 在棋盘中添加积木块  
  193.                 int curScore = calcScore(tmpchess, offsetX, offsetY);   // 计算当前情况下的得分  
  194.                 if (curScore > maxScore)  
  195.                 {  
  196.                     maxScore = curScore;  
  197.                     memcpy(nextChess, tmpchess, CHESS_AREA);  
  198.                 }  
  199.             }  
  200.         }  
  201.         memcpy(chess, nextChess, CHESS_AREA);  
  202.     }  
  203. }  
参考来源:   http://blog.csdn.net/linyunzju/article/details/7686822
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
完全原创的一个java俄罗斯方块游戏,实现了网络对战、道具使用、背景音乐播放、音效播放等功能。但网络对战和道具使用部分尚有些小问题,仍需要测试,因为没时间做了,发上来供大家下载,如果哪位有兴趣,想一起研究,可发邮件至lijiangui2002@163.com 类列表: backgroundmusic.java背景音乐播放类 blockcanvas.java方块类 bomp.java炸弹类(炸弹的消行规则是坠毁所占行数的方块) control.java主类 createdialog.java对话框类 data.java游戏与地图数据接口 gamecontrol.java游戏控制类 imagecapture.java图像采集与发送类 imageshow.java图像接收与显示类 jframe.java界面GUI类 nextpanel.java下一个方块画布类 soundeffect.java音效播放类 -------------------------------------------------------------------- 说明,内含编译好的j可执行jar程序,在正确安装jre的计算机上双击游戏程序即可运行,如果没有正确安装jre,可以编译游戏源文件运行。游戏主类为control.java ---------------------------------- 最初开发时,我把它定义一个比较有创意的游戏,但是最终因为没有时间而作罢,我的目的是游戏能够利用道具进行网络对攻,以增加游戏的趣味性。因为时间,我只设计出一种道具——炸弹,更糟糕的是,这唯一的一种道具都没有实现网络对攻, 只能随机地出现,这是让我很遗憾的地方。所以,哪位朋友对这个游戏有兴趣的话,咱们可以共同研究研究
提供的源码资源涵盖了安卓应用、小程序、Python应用和Java应用等多个领域,每个领域都包含了丰富的实例和项目。这些源码都是基于各自平台的最新技术和标准编写,确保了在对应环境下能够无缝运行。同时,源码中配备了详细的注释和文档,帮助用户快速理解代码结构和实现逻辑。 适用人群: 这些源码资源特别适合大学生群体。无论你是计算机相关专业的学生,还是对其他领域编程感兴趣的学生,这些资源都能为你提供宝贵的学习和实践机会。通过学习和运行这些源码,你可以掌握各平台开发的基础知识,提升编程能力和项目实战经验。 使用场景及目标: 在学习阶段,你可以利用这些源码资源进行课程实践、课外项目或毕业设计。通过分析和运行源码,你将深入了解各平台开发的技术细节和最佳实践,逐步培养起自己的项目开发和问题解决能力。此外,在求职或创业过程中,具备跨平台开发能力的大学生将更具竞争力。 其他说明: 为了确保源码资源的可运行性和易用性,特别注意了以下几点:首先,每份源码都提供了详细的运行环境和依赖说明,确保用户能够轻松搭建起开发环境;其次,源码中的注释和文档都非常完善,方便用户快速上手和理解代码;最后,我会定期更新这些源码资源,以适应各平台技术的最新发展和市场需求。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值